//
//  LivePhotoCreater.swift
//  LivePhotoDemoSwift
//
//  Created by TSYH on 2024/5/16.
//  Copyright © 2024 Genady Okrain. All rights reserved.
//

import UIKit
import PhotosUI
import ExtensionsKit

public class LivePhotoCreater: NSObject {
    public static let shared = LivePhotoCreater()
    
    /// 创建并保存LivePhoto
    /// - Parameters:
    ///   - videoURL: 视频本地URL
    ///   - outputDirectory: LivePhoto资源保存文件夹
    ///   - completion: （LivePhoto视频URL, LivePhoto图片URL）
    public func saveLivePhoto(from videoURL: URL, outputDirectory: URL,
                       completion: ((URL?, URL?, String?) -> Void)?) {
        createLivePhotoResource(with: videoURL, outputDirectory: outputDirectory) { videoURL, imageURL, erMsg in
            guard let imageURL = imageURL, let videoURL = videoURL else {
                completion?(nil, nil, erMsg ?? "Generate resource failure")
                return
            }
            self.exportLivePhoto(videoURL: videoURL, imageURL: imageURL) { success, erMsg in
                if success {
                    completion?(videoURL, imageURL, nil)
                } else {
                    completion?(nil, nil, erMsg ?? "Save LivePhoto Failure")
                }
            }
        }
    }
    
    /// 根据视频创建LivePhoto, 显示
    /// - Parameters:
    ///   - videoURL: 视频本地URL
    ///   - outputDirectory: LivePhoto资源保存文件夹
    ///   - completion:
    public func makeLivePhoto(with videoURL: URL,
                       outputDirectory: URL,
                       completion: ((PHLivePhoto?, String?) -> Void)?) {
        createLivePhotoResource(with: videoURL, outputDirectory: outputDirectory) { videoURL, imageURL, erMsg in
            DispatchQueue.main.sync {
                guard let imageURL = imageURL, let videoURL = videoURL else {
                    completion?(nil, erMsg)
                    return
                }
                PHLivePhoto.request(withResourceFileURLs: [videoURL, imageURL],
                                    placeholderImage: nil,
                                    targetSize: .zero,
                                    contentMode: PHImageContentMode.aspectFit,
                                    resultHandler: { (livePhoto, info) -> Void in
                    completion?(livePhoto, info.description)
                })
            }
        }
    }
    
    /// 根据视频创建LivePhoto资源
    /// - Parameters:
    ///   - videoURL: 视频本地URL
    ///   - outputDirectory: LivePhoto资源保存文件夹
    ///   - completion:
//    public func makeLivePhotoResource(with videoURL: URL,
//                                      outputDirectory: URL,
//                                      completion: ((URL?, URL?, String?) -> Void)?) {
//        let asset = AVURLAsset(url: videoURL)
//        
//        // 截取一帧图片
//        let generator = AVAssetImageGenerator(asset: asset)
//        generator.appliesPreferredTrackTransform = true
//        let time = NSValue(time: CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)/2, preferredTimescale: asset.duration.timescale))
//        generator.generateCGImagesAsynchronously(forTimes: [time]) { _, image, _, _, _ in
//            guard let cgimage = image else {
//                completion?(nil, nil, "Generate image failure~")
//                return
//            }
//            let image = UIImage(cgImage: cgimage)
//            var data: Data? = image.jpegData(compressionQuality: 1.0)
//            var orgImageName = "-orgImage.jpg"
//            var outputImageName = "-IMG.JPG"
//            
//            if #available(iOS 17, *) {
//                data = image.heicData()
//                orgImageName = "-orgImage.heif"
//                outputImageName = "-IMG.HEIF"
//            }
//            guard let data = data else {
//                completion?(nil, nil, "Generate image failure~")
//                return
//            }
//                
//            // 创建文件夹
//            let _ = try? FileManager.default.createDirectory(atPath: outputDirectory.path, withIntermediateDirectories: true, attributes: nil)
//            
//            // 当前时间戳+随机字符串 作为文件名
//            let outputName: String = "\(Int(Date().timeIntervalSince1970))" + String.randomString(count: 8)
//            
//            // 视频截取帧图片保存地址
//            let originalImageURL = outputDirectory.appendingPathComponent(outputName + orgImageName)
//            try? data.write(to: originalImageURL, options: [.atomic])
//            
//            let imageOutputURL = outputDirectory.appendingPathComponent(outputName + outputImageName)
//            let videoOutputURL = outputDirectory.appendingPathComponent(outputName + "-IMG.MOV")
//            
//            /// 给视频、图片添加LivePhoto信息
//            let assetIdentifier = UUID().uuidString
//            LivePhotoJPEG(path: originalImageURL.path).write(imageOutputURL.path, assetIdentifier: assetIdentifier)
//            LivePhotoMOV(path: videoURL.path).write(videoOutputURL.path, assetIdentifier: assetIdentifier)
//            
//            completion?(videoOutputURL, imageOutputURL, nil)
//        }
//    }
    
    /// 导出LivePhoto到相册
    public func exportLivePhoto(videoURL: URL, imageURL: URL,
                         completion: ((Bool, String?) -> Void)?) {
        PHPhotoLibrary.shared().performChanges({ () -> Void in
            let creationRequest = PHAssetCreationRequest.forAsset()
            let options = PHAssetResourceCreationOptions()
            creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: videoURL, options: options)
            creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: imageURL, options: options)
        }, completionHandler: { (success, error) -> Void in
            completion?(success, error?.localizedDescription)
        })
    }
}

extension LivePhotoCreater {
    /// 根据视频创建LivePhoto资源
    /// - Parameters:
    ///   - videoURL: 视频本地URL
    ///   - outputDirectory: LivePhoto资源保存文件夹
    ///   - completion: (Live视频URL, Live图片URL, 错误信息)
    func createLivePhotoResource(with videoURL: URL, outputDirectory: URL, completion: ((URL?, URL?, String?) -> Void)?) {
        
        guard let metaURL = Bundle(for: self.classForCoder).url(forResource: "metadata", withExtension: "mov") else {
            completion?(nil, nil, "Metadata file don't exist")
            return
        }
        let videoConverter = Converter4Video(path: videoURL.path)
        
        // 创建文件夹
        let _ = try? FileManager.default.createDirectory(atPath: outputDirectory.path, withIntermediateDirectories: true, attributes: nil)
        
        // 当前时间戳+随机字符串 作为文件名
        let outputName: String = "\(Int(Date().timeIntervalSince1970))" + String.randomString(count: 8)
        let imageOutputURL = outputDirectory.appendingPathComponent(outputName + "-Live.heic")
        let videoOutputURL = outputDirectory.appendingPathComponent(outputName + "-Live.mov")
        
        let asset = AVURLAsset(url: videoURL, options: nil)
        Log("===video duration:\(CMTimeGetSeconds(asset.duration))")
        guard CMTimeGetSeconds(asset.duration) <= 3 else {
            completion?(nil, nil, "The video is too long, please try again")
            return
        }
        
        let assetIdentifier = UUID().uuidString
        let queue = DispatchQueue(label: "image")
        queue.async {
            // 视频写入LivePhoto信息
            videoConverter.write(dest: videoOutputURL.path, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
                guard success, FileManager.default.fileExists(atPath: videoOutputURL.path) else {
                    completion?(nil, nil, "Convert Failure")
                    return
                }
                guard let keyFrame = self.getKeyFrameImage(from: videoOutputURL) else {
                    return
                }
                let imageConverter = Converter4Image(image: keyFrame)
                // 图片写入LivePhoto信息
                imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
                
                guard FileManager.default.fileExists(atPath: imageOutputURL.path) else {
                    completion?(nil, nil, "Convert Failure")
                    return
                }
                
                completion?(videoOutputURL, imageOutputURL, nil)
            }
        }
        
        
        
        
//        let generator = AVAssetImageGenerator(asset: asset)
//        generator.appliesPreferredTrackTransform = true
////        generator.requestedTimeToleranceAfter = CMTimeMake(value: 1,timescale: 100)
//        generator.requestedTimeToleranceAfter = .zero
//        generator.requestedTimeToleranceBefore = .zero
//        var times = [NSValue]()
////        let time = CMTimeMakeWithSeconds(0.5*CMTimeGetSeconds(asset.duration), preferredTimescale: asset.duration.timescale)
//        let time = CMTimeMakeWithSeconds(0.1, preferredTimescale: asset.duration.timescale)
//        times.append(NSValue(time: time))
//        
//        generator.generateCGImagesAsynchronously(forTimes: times) { requestedTime, image, actualTime, result, error in
//            guard let cgimage = image else {
//                completion?(nil, nil, "Generate Frame Failure~")
//                return
//            }
//            
//            let imageConverter = Converter4Image(image: UIImage(cgImage: cgimage))
//            queue.async {
//                // 图片写入LivePhoto信息
////                imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
//                
//                // 视频写入LivePhoto信息
//                videoConverter.write(dest: videoOutputURL.path, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
//                    guard success else {
//                        completion?(nil, nil, "Convert Failure")
//                        return
//                    }
//                    guard FileManager.default.fileExists(atPath: videoOutputURL.path) else {
//                        completion?(nil, nil, "Convert Failure")
//                        return
//                    }
//                    
//                    guard let keyFrame = self.getKeyFrameImage(from: videoOutputURL) else {
//                        return
//                    }
//                    let imageConverter = Converter4Image(image: keyFrame)
//                    // 图片写入LivePhoto信息
//                    imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
//                    guard FileManager.default.fileExists(atPath: imageOutputURL.path) else {
//                        completion?(nil, nil, "Convert Failure")
//                        return
//                    }
//                    completion?(videoOutputURL, imageOutputURL, nil)
//                }
//            }
//        }
    }
    
    func getKeyFrameImage(from videoURL: URL) -> UIImage? {
        var percent: Float = 0.5
        let videoAsset = AVURLAsset(url: videoURL)
        Log("live video duration: \(CMTimeGetSeconds(videoAsset.duration))")
        if let stillImageTime = videoAsset.stillImageTime() {
            percent = Float(stillImageTime.value) / Float(videoAsset.duration.value)
        }
        guard let imageFrame = videoAsset.getAssetFrame(percent: percent) else { return nil }
        return imageFrame
    }
}

extension String {
    /// 获取指定长度随机字符串
    static func randomString(count: Int) -> String {
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        let randomString = String((0..<count).map{ _ in letters.randomElement()! })
        return randomString
    }
}
